#include <driver/view/section.h>
#include <driver/view/view.h>
#include <driver/view/env.h>
#include <driver/view/bitmap.h>
#include <driver/view/render.h>

int ViewRenderPutPixel(view_t *view, int x, int y, view_color_t color)
{
    if (!view)
        return -1;
    if (!view->section)
        return -1;
    if (x < 0 || x >= view->width || y < 0 || y >= view->height)
        return -1;
    view_color_t *buff = (view_color_t *)view->section->addr;
    buff[y * view->width + x] = color;
}

int ViewRenderGetPixel(view_t *view, int x, int y, view_color_t *color)
{
    if (!view)
        return -1;
    if (!view->section)
        return -1;
    if (x < 0 || x >= view->width || y < 0 || y >= view->height)
        return -1;
    view_color_t *buff = (view_color_t *)view->section->addr;
    *color = buff[y * view->width + x];
    return 0;
}

int ViewRenderClear(view_t *view)
{
    if (!view)
        return -1;
    if (!view->section)
        return -1;
    view_color_t *buff = (view_color_t *)view->section->addr;

    int i, j;
    for (j = 0; j < view->height; j++)
    {
        for (i = 0; i < view->width; i++)
        {
            buff[j * view->width + i] = 0;
        }
    }
    return 0;
}

void ViewRenderVline(view_t *view, int x, int y1, int y2, view_color_t color)
{
    if (!view)
        return;
    if (!view->section)
        return;

    view_color_t *buff = (view_color_t *)view->section->addr;
    int off;
    int i;

    if (x < 0 || x > view->width - 1)
        return;
    if (y1 < 0 || y2 < 0)
        return;
    if (y1 >= view->height || y2 >= view->height)
        return;
  
    // vertional
    for (i = 0; i <= y2 - y1; i++)
    {  
        off = view->width * (y1 + i) + x;
        if (off > view->width * view->height - 1)
            return;
        *(buff + off) = color;
    }
}

void ViewRenderHline(view_t *view, int y, int x0, int x1, view_color_t color)
{
    if (!view)
        return;
    if (!view->section)
        return;

    view_color_t *buff = (view_color_t *)view->section->addr;
    int off;
    int i;

    if (y < 0 || y > (view->height - 1))
        return;
    if (x0 < 0 || x1 < 0)
        return;
    if (x0 >= view->width && x1 >= view->width)
        return;

    off = (view->width * y + x0);
    if (off > view->width * view->height - 1)
        return;

    // horzontion
    for (i = 0; i <= x1 - x0; i++)
    {
        *(buff + off + i) = color;
    }
}

void ViewRenderLine(view_t *view, int x1, int y1, int x2, int y2, view_color_t color)
{
    if (!view)
        return;
    if (!view->section)
        return;

    if (x1 == x2)
    {
        if (y1 < y2)
        {
            ViewRenderVline(view, x1, y1, y2, color);
        }
        else
        {
            ViewRenderVline(view, x1, y2, y1, color);
        }
        return;
    }
    else
    {
        if (y1 == y2)
        {
            if (x1 < x2)
            {
                ViewRenderHline(view, y1, x1, x2, color);
            }
            else
            {
                ViewRenderHline(view, y1, x2, x1, color);
            }
        }
        return;
    }
    int i, x, y, len, dx, dy;
    dx = x2 - x1;
    dy = y2 - y2;

    x = x1 << 10;
    y = y1 << 10;

    if (dx < 0)
        dx = -dx;

    if (dy < 0)
        dy = -dy;

    if (dx >= dy)
    {
        len = dx + 1;

        if (x1 > x2)
        {
            dx = -1024;
        }
        else
        {
            dx = 1024;
        }

        if (y1 <= y2)
        {
            dy = ((y2 - y1 + 1) << 10) / len;
        }
        else
        {
            dy = ((y2 - y1 - 1) << 10) / len;
        }
    }
    else
    {
        len = dy + 1;

        if (y1 > y2)
        {
            dy = -1024;
        }
        else
        {
            dy = 1024;
        }

        if (x1 <= x2)
        {
            dx = ((x2 - x1 + 1) << 10) / len;
        }
        else
        {
            dx = ((x2 - x1 - 1) << 10) / len;
        }
    }
    for (i = 0; i < len; i++)
    {
        ViewRenderPutPixel(view, (x >> 10), (y >> 10), color);
        x += dx;
        y += dy;
    }
}

int ViewRenderRectEx(view_t *view, int x1, int y1, int x2, int y2, view_color_t color)
{
    if (!view)
        return -1;
    if (!view->section)
        return -1;

    // left
    ViewRenderVline(view, x1, y1, y2, color);
    // right
    ViewRenderVline(view, x2, y1, y2, color);
    // top
    ViewRenderHline(view, y1, x1, x2, color);
    // bottom
    ViewRenderHline(view, y2, x1, x2, color);
    return 0;
}

int ViewRenderRectfillEx(view_t *view, int x1, int y1, int x2, int y2, view_color_t color)
{
    if (!view)
        return -1;
    if (!view->section)
        return -1;

    int i;
    for (i = 0; i <= y2 - y1; i++)
    {
        ViewRenderHline(view, y1 + i, x1, x2, color);
    }
    return 0;
}

int ViewRenderRect(view_t *view, int x, int y, uint32_t width, int height, view_color_t color)
{
    if (!view)
        return -1;
    if (!view->section)
        return -1;
    return ViewRenderRectEx(view, x, y, x + width - 1, y + height - 1, color);
}

void ViewRenderRectfill(view_t *view, int x, int y, uint32_t width, uint32_t height, view_color_t color)
{
    if (!view)
        return;
    if (!view->section)
        return;
    int i, j;
    int vx, vy;
    for (j = 0; j < height; j++)
    {
        vy = y + j;
        if (vy >= view->height)
        {
            break;
        }
        for (i = 0; i < width; i++)
        {
            vx = x + i;
            if (vx >= view->width)
            {
                break;
            }
            ViewRenderPutPixel(view, vx, vy, color);
        }
    }
    return;
}

int ViewRenderBitblt(view_t *view, int x, int y, view_bitmap_t *bmp, int bx, int by, int width, int height)
{
    if (!view)
        return -1;

    if (!view->section)
        return -1;

    // check limit
    if (width > bmp->width)
        return -1;
    if (height > bmp->height)
        return -1;

    //KPrint("[view] render bitblt to %d %d bmp[%d %d %d %d]\n", x, y, bx, by, width, height);

    // cut size
    int w = min(width, bmp->width);
    int h = min(height, bmp->height);
    if (w <= 0 || h <= 0)
    {
        return -1;
    }

    view_color_t color;
    int vx, vy;
    int bx2, by2;

    int vy2 = min((y + h), view->height);
    int vx2 = min((x + w), view->width);

    for (vy = y, by2 = by; vy < vy2; vy++, by2++)
    {
        for (vx = x, bx2 = bx; vx < vx2; vx++, bx2++)
        {
            color = ViewBitmapGetPixelFast(bmp, bx2, by2);
            if ((color >> 24) & 0xff)
            {
                ViewRenderPutPixelFast(view, vx, vy, color);
            }
        }
    }
    //KPrint("[view] render bitblt ok\n");
    return 0;
}

int ViewRenderDrawShade(view_t *shade, view_rect_t *rect, int draw)
{
    if (!shade || !rect)
        return -1;

    view_color_t color;

    if (draw)
    {
        color = VIEW_BLACK;
        // drag rect
        ViewRenderRectfill(shade, rect->x + 1, rect->y + 1, rect->w.uw - 1, 1, color);
        ViewRenderRectfill(shade, rect->x + 1, rect->y + 1, 1, rect->h.uh - 1, color);
        ViewRenderRectfill(shade, rect->x + rect->w.uw - 1, rect->y + 1, 1, rect->h.uh - 2, color);
        ViewRenderRectfill(shade, rect->x, rect->y + rect->h.uh - 2, rect->w.uw - 1, 1, color);

        color = VIEW_WHITE;
        // drag rect
        ViewRenderRectfill(shade, rect->x, rect->y, rect->w.uw - 1, 1, color);
        ViewRenderRectfill(shade, rect->x, rect->y, 1, rect->h.uh - 1, color);
        ViewRenderRectfill(shade, rect->x + rect->w.uw - 2, rect->y, 1, rect->h.uh - 1, color);
        ViewRenderRectfill(shade, rect->x, rect->y + rect->h.uh - 2, rect->w.uw - 1, 1, color);

        ViewRefreshRect(shade, rect->x, rect->y, rect->w.uw, 2);
        ViewRefreshRect(shade, rect->x, rect->y, 2, rect->h.uh);
        ViewRefreshRect(shade, rect->x + rect->w.uw - 2, rect->y, 2, rect->h.uh);
        ViewRefreshRect(shade, rect->x, rect->y + rect->h.uh - 2, rect->w.uw, 2);
    }
    else
    {
        color = VIEW_NONE;
        ViewRenderRectfill(shade, rect->x, rect->y, rect->w.uw, 2, color);
        ViewRenderRectfill(shade, rect->x, rect->y, 2, rect->h.uh, color);
        ViewRenderRectfill(shade, rect->x + rect->w.uw - 2, rect->y, 2, rect->h.uh, color);
        ViewRenderRectfill(shade, rect->x, rect->y + rect->h.uh - 2, rect->w.uw, 2, color);

        ViewRefreshRectFromBottom(shade, rect->x, rect->y, rect->w.uw, 2);
        ViewRefreshRectFromBottom(shade, rect->x, rect->y, 2, rect->h.uh);
        ViewRefreshRectFromBottom(shade, rect->x + rect->w.uw - 2, rect->y, 2, rect->h.uh);
        ViewRefreshRectFromBottom(shade, rect->x, rect->y + rect->h.uh - 2, rect->w.uw, 2);
    }
}